﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PMisuseAn.io;
using System.Collections.Specialized;
using System.Collections;
using PMisuseAn.util;
using System.Text.RegularExpressions;

namespace PMisuseAn.behaviour.model
{
    public class VulnerabilityAnalyser
    {
        public List<List<Threat>> aggregationThreats;
        public List<Threat> aggregationCachePotentialThreats;
        List<Threat> aggregationAllTimeCacheThreatCheckList;
        
        public bool misuseFound = false;
        public bool potentialMisuseFound = false;

        bool allTimeAggregateCall = false;
        
        List<Policy> aggPolicyCheckList;
        string oringinalMessage;
        string originalContext;

        public VulnerabilityAnalyser()
        {
            aggregationThreats = new List<List<Threat>>();
            aggregationCachePotentialThreats = new List<Threat>();
            aggregationAllTimeCacheThreatCheckList = new List<Threat>();
        }

        public void checkAggregationMisuse(Agent sourceAgent, Agent sendAgent, Agent receiveAgent,
           Agent subjectAgent, State message_s, Transition message_t, List<Object> parameterisedContextInstances_y,
           PolicyStatementAnalyser statAnalyser, Dictionary<Dictionary<Agent, Agent>, ListDictionary> sendReceiveContextAgent, Context contextInstance, MisuseAnalyser misuseAnalyser, List<Threat> newThreats)
        {    
            allTimeAggregateCall = false;

            State activeState = null;
            Transition activeTransition = null;
            oringinalMessage = getThreatMessageTrans(message_s, message_t, sendAgent, receiveAgent, subjectAgent);
            originalContext = getThreatMessageContext(parameterisedContextInstances_y);


            foreach (Object obj in parameterisedContextInstances_y)
            {
                Attribute atte = obj as Attribute;
                if (atte != null)
                {
                    if (atte.activeDomain != null && atte.activeDomain.Count() > 0)
                    {
                        bool contained = false;
                        if(message_s != null)
                        {
                            //check that message_s does not contain atte
                            foreach(Attribute att in message_s.activeAction.parameterisedOperationalAttributes)
                            {
                                if(att.name.Equals(atte.name))
                                {
                                    contained = true;
                                }
                            }
                        }
                        else if(message_t != null)
                        {
                            //check that message_t does not contain atte
                            foreach(Attribute att in message_t.activeEvent.parameterisedOperationalAttributes)
                            {
                                if(att.name.Equals(atte.name))
                                {
                                    contained = true;
                                }
                            }
                        }
                        if(contained == true)
                        {
                            continue;
                        }

                        MisUseAnObjectsDB.loadAggregateAttributes(atte, MainWindow.clusterName);
                        List<string> aggStatements = atte.aggregation_statements;

                        foreach (string aggStatement in aggStatements)
                        {
                            //List<Threat> newAggregationThreats;
                            //newAggregationThreats = new List<Threat>();

                            List<Attribute> attributesInStatement = new AggregationStatementAnalyser(aggStatement).attributesInStatement;
                            if (message_s != null)
                            {
                                activeState = message_s;
                                if (activeState.activeAction != null)
                                {
                                    bool treated = false;
                                    foreach (Attribute att in activeState.activeAction.parameterisedOperationalAttributes)
                                    {
                                        if (treated == true)
                                        {
                                            continue;
                                        }
                                        if (att.activeDomain != null && att.activeDomain.Length != 0)
                                        {
                                            List<string> attsInMessage = new List<string>();
                                            foreach (Attribute attInStat in attributesInStatement)
                                            {
                                                if (!attInStat.name.Equals(atte.name))
                                                {
                                                    foreach (Attribute att1 in activeState.activeAction.parameterisedOperationalAttributes)
                                                    {
                                                        if (att1.name.Equals(attInStat.name))
                                                        {
                                                            attsInMessage.Add(att1.name);
                                                        }
                                                    }
                                                }
                                            }
                                            if (attsInMessage.Count != (attributesInStatement.Count - 1))
                                            {
                                                continue;
                                            }

                                            treated = true;
                                            List<Policy> aggPolicyChecklist = new List<Policy>();
                                            misuseAnalyser.genPolicyChecklist(atte, aggPolicyChecklist);

                                            foreach (Policy policy in aggPolicyChecklist)
                                            {
                                                statAnalyser.ifThenUnlessContentTokenisation(policy.statement);
                                                vulnerableTransmissionPolicyTest(sendAgent, receiveAgent, subjectAgent, 
                                                                message_s, message_t,parameterisedContextInstances_y,
                                                                policy, statAnalyser, contextInstance, aggStatement,
                                                                newThreats);

                                                //vulnerableTransmissionPolicyTest(vag, policy, statAnalyser, contextInstance);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (message_t != null)
                            {
                                activeTransition = message_t;
                                if (activeTransition.activeEvent != null)
                                {
                                    bool treated = false;
                                    foreach (Attribute att in activeTransition.activeEvent.parameterisedOperationalAttributes)
                                    {
                                        if (treated == true)
                                        {
                                            continue;
                                        }
                                        if (att.activeDomain != null && att.activeDomain.Length != 0)
                                        {
                                            List<string> attsInMessage = new List<string>();
                                            foreach (Attribute attInStat in attributesInStatement)
                                            {
                                                if (!attInStat.name.Equals(atte.name))
                                                {
                                                    foreach (Attribute att1 in activeTransition.activeEvent.parameterisedOperationalAttributes)
                                                    {
                                                        if (att1.name.Equals(attInStat.name))
                                                        {
                                                            attsInMessage.Add(att1.name);
                                                        }
                                                    }
                                                }
                                            }
                                            if (attsInMessage.Count != (attributesInStatement.Count - 1))
                                            {
                                                continue;
                                            }

                                            treated = true;

                                            List<Policy> aggPolicyChecklist = new List<Policy>();
                                            misuseAnalyser.genPolicyChecklist(atte, aggPolicyChecklist);

                                            foreach (Policy policy in aggPolicyChecklist)
                                            {
                                                statAnalyser.ifThenUnlessContentTokenisation(policy.statement);
                                                vulnerableTransmissionPolicyTest(sendAgent, receiveAgent, subjectAgent,
                                                                message_s, message_t, parameterisedContextInstances_y,
                                                                policy, statAnalyser, contextInstance, aggStatement,
                                                                newThreats);

                                                //vulnerableTransmissionPolicyTest(vag, policy, statAnalyser, contextInstance);
                                            }
                                        }
                                    }
                                }
                            }
                            pruneThroughAggregateAllTimeHenceforthCacheThreat(parameterisedContextInstances_y, contextInstance, statAnalyser, newThreats, sendAgent, receiveAgent, subjectAgent,  message_s,  message_t);
                            pruneThroughAggregateCachePotentialThreats(parameterisedContextInstances_y, contextInstance, statAnalyser, newThreats, sendAgent, receiveAgent, subjectAgent,  message_s,  message_t);

                            //if (newAggregationThreats.Count > 0)
                            //{
                            //    aggregationThreats.Add(newAggregationThreats);
                            //}
                        }
                    }
                }
            }
        }

         
        //public void vulnerableTransmissionPolicyTest(VulnerableAggTransmission vag, Policy policy, PolicyStatementAnalyser statAnalyser, Context contextInstance)
        public void vulnerableTransmissionPolicyTest(Agent sendAgent, Agent receiveAgent,Agent subjectAgent, State message_s, Transition message_t,
                                                        List<Object> parameterisedContextInstances_y, Policy policy, PolicyStatementAnalyser statAnalyser,
                                                        Context contextInstance, string aggStatement, List<Threat> newAggregationThreats)
        {
            if (!policy.statement.Equals("DO[NILL]"))
            {
                statAnalyser.ifThenUnlessContentTokenisation(policy.statement);
                bool applicableIFPolicySegment = true;
                //bool applicableIFPolicySegment = ApplicableIfTest.applicableIfAnalysis(vag.h_sendAgent,
                //                                vag.h_receiveAgent, vag.h_subjectAgent, vag.h_message_s, vag.h_message_t,
                //                                vag.h_parameterisedContextInstances, statAnalyser, contextInstance);


                string thenTemporalType = getThenTemporalType(policy, statAnalyser);
                bool thenSatisfied = false;
                bool unlessSatisfied = false;

                if (applicableIFPolicySegment == true)
                {
                    string unlessTemporalType = null;

                    switch (thenTemporalType)
                    {
                        case "LAST-TIME":
                            thenSatisfied = SatisfiedLastTimeTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                               subjectAgent, statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                        case "PREVIOUSLY":
                            thenSatisfied = SatisfiedPreviouslyTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                               subjectAgent, statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                        case "EVENTUALLY":
                            break;
                        case "HENCEFORTH":
                            thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(sendAgent, receiveAgent,
                                                           subjectAgent, message_s, message_t, parameterisedContextInstances_y,
                                                           statAnalyser.tokenisedUnlessContent, contextInstance);
                            break;
                        case "NEXT-TIME":
                            break;
                        case "ALL-TIME":
                            //DO satisfy previously test and add to allTimeCacheThreatChecks
                            thenSatisfied = SatisfiedAllTimeTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                               subjectAgent, statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                    }

                    if (thenSatisfied == false)
                    {
                        unlessTemporalType = getUnlessTemporalType(policy, statAnalyser);

                        switch (unlessTemporalType)
                        {
                            case "LAST-TIME":
                                unlessSatisfied = SatisfiedLastTimeTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                                subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "PREVIOUSLY":
                                unlessSatisfied = SatisfiedPreviouslyTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                               subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "EVENTUALLY":
                                break;
                            case "HENCEFORTH":
                                thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(sendAgent, receiveAgent,
                                                               subjectAgent, message_s, message_t, parameterisedContextInstances_y,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "NEXT-TIME":
                                break;
                            case "ALL-TIME":
                                //DO satisfy previously test and add to allTimeCacheThreatChecks
                                unlessSatisfied = SatisfiedAllTimeTest.satisfiedAnalysis(sendAgent, receiveAgent,
                                                             subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                        }
                    }


                    if (thenTemporalType.Equals("LAST-TIME")
                       || thenTemporalType.Equals("PREVIOUSLY")
                        || thenTemporalType.Equals("ALL-TIME")
                        || thenTemporalType.Equals("HENCEFORTH"))
                    {
                        if (thenSatisfied == false && unlessSatisfied == false)
                        {
                            Threat threat = new Threat();
                            //threat.comments = "AGGREGATION-CHECK";
                            threat.comments = "INFERRED-AUTHORISATION-FAILURE";
                            threat.subjectAgent = subjectAgent;
                            threat.sendAgent = sendAgent;
                            threat.recieveAgent = receiveAgent;
                            threat.violatingParameterisedContextInstances = parameterisedContextInstances_y;
                            threat.violatedPolicy = policy;
                            threat.timestamp = DateTime.Now;
                            if (message_s != null)
                            {
                                threat.message_s = message_s;
                            }
                            else if (message_t != null)
                            {
                                threat.message_t = message_t;
                            }
                            threat.rationales.Add("inference:", aggStatement);
                            threat.rationales.Add("violatingContext:", originalContext);
                            threat.rationales.Add("messageTrans:", oringinalMessage);

                            threat.rationalle = "[Transmission policy will be violated by this context]";
                            threat.threatType = Threat.ThreatType.currentThreat;

                            newAggregationThreats.Add(threat);
                            misuseFound = true;
                        }
                    }

                    if ((thenTemporalType.Equals("ALL-TIME") || thenTemporalType.Equals("HENCEFORTH"))
                       && (thenSatisfied == true || unlessSatisfied == true))
                    {
                        Threat threat = new Threat();
                        threat.subjectAgent = subjectAgent;
                        threat.sendAgent = sendAgent;
                        threat.recieveAgent = receiveAgent;
                        threat.violatingParameterisedContextInstances = parameterisedContextInstances_y;
                        threat.timestamp = DateTime.Now;
                        threat.violatedPolicy = policy;
                        if (message_s != null)
                        {
                            threat.message_s = message_s;
                        }
                        else if (message_t != null)
                        {
                            threat.message_t = message_t;
                        }
                        threat.rationales.Add("inference:", aggStatement);
                        threat.rationales.Add("violatingContext:", originalContext);
                        threat.rationales.Add("messageTrans:", oringinalMessage);

                        aggregationAllTimeCacheThreatCheckList.Add(threat);
                    }
                    if (thenTemporalType.Equals("EVENTUALLY")
                            || thenTemporalType.Equals("NEXT-TIME"))
                    {
                        Threat threat = new Threat();
                        threat.comments = "INFERRED-UNFULFILLED-OBLIGATION";
                        threat.subjectAgent = subjectAgent;
                        threat.sendAgent = sendAgent;
                        threat.recieveAgent = receiveAgent;
                        threat.violatingParameterisedContextInstances = parameterisedContextInstances_y;
                        threat.timestamp = DateTime.Now;
                        threat.violatedPolicy = policy;
                        if (message_s != null)
                        {
                            threat.message_s = message_s;
                        }
                        else if (message_t != null)
                        {
                            threat.message_t = message_t;
                        }

                        threat.rationales.Add("inference:", aggStatement);
                        threat.rationales.Add("violatingContext:", originalContext);
                        threat.rationales.Add("messageTrans:", oringinalMessage);

                        threat.rationalle = "[Transmission policy not yet satisfied]";
                        threat.threatType = Threat.ThreatType.futureThreat;

                        aggregationCachePotentialThreats.Add(threat);

                        potentialMisuseFound = true;
                    }

                }
            }
        }

        private List<VulnerableAggTransmission> extractVulnerableTransmissionsFromHistory(Agent receiveAgent,
         Agent subjectAgent, Agent sourceAgent, Attribute att, List<Attribute> attributesInAggStatement, string aggregationStatement, string originalMessage, string originalContext)
        {
            List<VulnerableAggTransmission> vulnerableTransmissions = new List<VulnerableAggTransmission>();

            foreach (Attribute attx in attributesInAggStatement)
            {
                if (!attx.name.Equals(att.name)) //checks attributes other than the current message attribute
                {
                    //check if attx domain value has been sent to receiver agent before
                    //Stack<string> stackedInteractionNames = HistorySerialisationEngine.getStackedInteractionList(sourceAgent.agentName);
                    Stack<int> stackedInteractionSeqno = HistorySerialisationEngine.getStackedInteractionList(sourceAgent.agentName);
                    foreach (int interactionSeqNo in stackedInteractionSeqno)
                    {
                        HistoryItem ih = HistorySerialisationEngine.deSerialiseInteractionHistory(interactionSeqNo, EmulationEnvironmentWindow.sourceAgentName);

                        int counter = 0;
                        while (ih == null && counter < 10)
                        {
                            ih = HistorySerialisationEngine.deSerialiseInteractionHistory(interactionSeqNo, EmulationEnvironmentWindow.sourceAgentName);
                            counter++;
                        }

                        //if (ih == null)
                        //    continue;

                        ListDictionary hi = ih.interactionHistoryItem;
                        //foreach (KeyValuePair<List<Object>, Dictionary<Dictionary<Agent, Agent>, ListDictionary>> historyItem in hi)
                        foreach (DictionaryEntry historyItem in hi)
                        {
                            List<Object> h_parameterisedContextInstances = (List<Object>)historyItem.Key;
                            Dictionary<Dictionary<Agent, Agent>, ListDictionary> h_sendReceiveContextAgent = (Dictionary<Dictionary<Agent, Agent>, ListDictionary>)historyItem.Value;

                            State h_message_s = null;
                            Transition h_message_t = null;
                            Agent h_sendAgent = null;
                            Agent h_receiveAgent = null;
                            Agent h_subjectAgent = null;

                            foreach (KeyValuePair<Dictionary<Agent, Agent>, ListDictionary> pairx in h_sendReceiveContextAgent)
                            {
                                Dictionary<Agent, Agent> messageHeader = pairx.Key;
                                foreach (KeyValuePair<Agent, Agent> sr in messageHeader)
                                {
                                    h_sendAgent = sr.Key;
                                    h_receiveAgent = sr.Value;
                                }

                                ListDictionary messageBody = pairx.Value;
                                foreach (DictionaryEntry mes in messageBody)
                                {
                                    h_subjectAgent = (Agent)mes.Key;
                                    if (mes.Value is State)
                                    {
                                        h_message_s = (State)mes.Value;
                                        h_message_t = null;
                                    }
                                    else if (mes.Value is Transition)
                                    {
                                        h_message_t = (Transition)mes.Value;
                                        h_message_s = null;
                                    }
                                }

                                if (receiveAgent.agentName.Equals(h_receiveAgent.agentName) &&
                                    subjectAgent.agentName.Equals(h_subjectAgent.agentName))
                                {
                                    //iterate through h_message_s/t and check if the operational attributes contains attx;
                                    //if yes add to list of vulnerable attributes
                                    if (h_message_s != null)
                                    {
                                        foreach (Attribute h_att in h_message_s.activeAction.parameterisedOperationalAttributes)
                                        {
                                            if (h_att.name.Equals(attx.name))
                                            {
                                                VulnerableAggTransmission vulnTrans = new VulnerableAggTransmission(
                                                    h_att,
                                                    h_message_s,
                                                    null,
                                                    h_parameterisedContextInstances,
                                                    h_sendReceiveContextAgent,
                                                    h_sendAgent,
                                                    h_receiveAgent,
                                                    h_subjectAgent,
                                                    aggregationStatement,
                                                    interactionSeqNo,
                                                    originalMessage,
                                                    originalContext);

                                                vulnerableTransmissions.Add(vulnTrans);
                                            }
                                        }
                                    }
                                    else if (h_message_t != null)
                                    {
                                        foreach (Attribute h_att in h_message_t.activeEvent.parameterisedOperationalAttributes)
                                        {
                                            if (h_att.name.Equals(attx.name))
                                            {
                                                VulnerableAggTransmission vulnTrans = new VulnerableAggTransmission(
                                                    h_att,
                                                    null,
                                                    h_message_t,
                                                    h_parameterisedContextInstances,
                                                    h_sendReceiveContextAgent,
                                                    h_sendAgent,
                                                    h_receiveAgent,
                                                    h_subjectAgent,
                                                    aggregationStatement,
                                                    interactionSeqNo,
                                                    originalMessage,
                                                    originalContext);

                                                vulnerableTransmissions.Add(vulnTrans);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return vulnerableTransmissions;
        }
        
     
        private string getThreatViolatingContext(Threat threat)
        {
            string violatingContext = "";
            int j = 0;
            //int k = 0;
            foreach (Object obj in threat.violatingParameterisedContextInstances)
            {
                Attribute atte = obj as Attribute;
                if (atte != null)
                {
                    if (atte.activeDomain != null && atte.activeDomain.Count() > 0)
                    {
                        violatingContext = violatingContext + atte.name + "=" + atte.activeDomain;
                    }
                    else
                    {
                        violatingContext = violatingContext + atte.name + "= ?";
                    }
                }
                else
                {
                    GroupFunction gf = obj as GroupFunction;
                    if (gf != null)
                    {
                        string membershipFunction = gf.functionName + "(" + gf.agentName + ", " + gf.groupName + ")";
                        violatingContext = violatingContext + membershipFunction;
                    }
                }

                if (j < threat.violatingParameterisedContextInstances.Count() - 1)
                {
                    violatingContext = violatingContext + ", ";
                }
                j = j + 1;

                //if (k == 3)
                //{
                //    violatingContext = violatingContext + "\r\n";
                //    k = 0;
                //}
                //else
                //{
                //    k = k + 1;
                //}
            }

            return violatingContext;

        }

        private string getThreatMessageContext(List<Object> parameterisedContextInstances)
        {
            string messageContext = "";
            int j = 0;
            //int km = 0;
            foreach (Object obj in parameterisedContextInstances)
            {
                Attribute atte = obj as Attribute;
                if (atte != null)
                {
                    if (atte.activeDomain != null && atte.activeDomain.Count() > 0)
                    {
                        messageContext = messageContext + atte.name + "=" + atte.activeDomain;
                    }
                    else
                    {
                        messageContext = messageContext + atte.name + "= ?";
                    }
                }
                else
                {
                    GroupFunction gf = obj as GroupFunction;
                    if (gf != null)
                    {
                        string membershipFunction = gf.functionName + "(" + gf.agentName + ", " + gf.groupName + ")";
                        messageContext = messageContext + membershipFunction;
                    }
                }

                if (j < parameterisedContextInstances.Count() - 1)
                {
                    messageContext = messageContext + ", ";
                }

                //if (km == 3)
                //{
                //    messageContext = messageContext + "\r\n";
                //    km = 0;
                //}
                //km = km + 1;

                j = j + 1;
            }

            return messageContext;
        }

        private string getThreatMessageTrans(State message_s, Transition message_t, Agent sendAgent, Agent recieveAgent, Agent subjectAgent)
        {
            string threatMessageTransition = "";
            threatMessageTransition = threatMessageTransition + sendAgent.agentName + "→[";
            threatMessageTransition = threatMessageTransition + subjectAgent.agentName + "(";

            State activeState = null;
            Transition activeTransition = null;
            if (message_s != null)
            {
                activeState = message_s;
                int i = 0;
                if (activeState.activeAction != null)
                {
                    int km = 0;
                    foreach (Attribute att in activeState.activeAction.parameterisedOperationalAttributes)
                    {
                        threatMessageTransition = threatMessageTransition + att.name + "=" + att.activeDomain;

                        if (i < activeState.activeAction.parameterisedOperationalAttributes.Count - 1)
                        {
                            threatMessageTransition = threatMessageTransition + ",";
                        }

                        //if (km == 3)
                        //{
                        //    threatMessageTransition = threatMessageTransition + "\r\n" + "    ";
                        //    km = 0;
                        //}
                        km = km + 1;
                        i = i + 1;
                    }
                }
            }
            else if (message_t != null)
            {

                activeTransition = message_t;
                int i = 0;
                if (activeTransition.activeEvent != null)
                {
                    int km = 0;
                    foreach (Attribute att in activeTransition.activeEvent.parameterisedOperationalAttributes)
                    {
                        threatMessageTransition = threatMessageTransition + att.name + "=" + att.activeDomain;

                        if (i < activeTransition.activeEvent.parameterisedOperationalAttributes.Count - 1)
                        {
                            threatMessageTransition = threatMessageTransition + ",";                            
                        }
                        //if (km == 3)
                        //{
                        //    threatMessageTransition = threatMessageTransition + "\r\n" + "    ";
                        //    km = 0;
                        //}
                        km = km + 1;

                        i = i + 1;
                    }
                }
            }
            threatMessageTransition = threatMessageTransition + ")]→" + recieveAgent.agentName;

            if (message_s != null)
            {
                threatMessageTransition = threatMessageTransition + "        #:" + message_s.name;
            }
            else if (message_t != null)
            {
                threatMessageTransition = threatMessageTransition + "        #:" + message_t.transitionName;
            }
            return threatMessageTransition;
        }
        
        private string getThreatMessageTrans(Threat threat)
        {
            string threatMessageTransition = "";
            threatMessageTransition = threatMessageTransition + threat.sendAgent.agentName + "→[";
            threatMessageTransition = threatMessageTransition + threat.subjectAgent.agentName + "(";

            State activeState = null;
            Transition activeTransition = null;
            if (threat.message_s != null)
            {
                activeState = threat.message_s;
                int i = 0;
                if (activeState.activeAction != null)
                {
                    int km = 0;
                    foreach (Attribute att in activeState.activeAction.parameterisedOperationalAttributes)
                    {
                        threatMessageTransition = threatMessageTransition + att.name + "=" + att.activeDomain;

                        if (i < activeState.activeAction.parameterisedOperationalAttributes.Count - 1)
                        {
                            threatMessageTransition = threatMessageTransition + ",";
                        }

                        //if (km == 3)
                        //{
                        //    threatMessageTransition = threatMessageTransition + "\r\n" + "    ";
                        //    km = 0;
                        //}
                        km = km + 1;
                        i = i + 1;
                    }
                }
            }
            else if (threat.message_t != null)
            {

                activeTransition = threat.message_t;
                int i = 0;
                if (activeTransition.activeEvent != null)
                {
                    int km = 0;
                    foreach (Attribute att in activeTransition.activeEvent.parameterisedOperationalAttributes)
                    {
                        threatMessageTransition = threatMessageTransition + att.name + "=" + att.activeDomain;

                        if (i < activeTransition.activeEvent.parameterisedOperationalAttributes.Count - 1)
                        {
                            threatMessageTransition = threatMessageTransition + ",";
                        }

                        //if (km == 3)
                        //{
                        //    threatMessageTransition = threatMessageTransition + "\r\n" + "    ";
                        //    km = 0;
                        //}
                        km = km + 1;
                        i = i + 1;
                    }
                }
            }
            threatMessageTransition = threatMessageTransition + ")]→" + threat.recieveAgent.agentName;

            if (threat.message_s != null)
            {
                threatMessageTransition = threatMessageTransition + "        #:" + threat.message_s.name;
            }
            else if (threat.message_t != null)
            {
                threatMessageTransition = threatMessageTransition + "        #:" + threat.message_t.transitionName;
            }
            return threatMessageTransition;
        }
        
        public string getThenTemporalType(Policy policy, PolicyStatementAnalyser statAnalyser)
        {
            string thenTemporalType = null;

            if (!policy.statement.Equals("DO[NILL]"))
            {
                statAnalyser.ifThenUnlessContentTokenisation(policy.statement);
                foreach (DictionaryEntry policyItem in statAnalyser.tokenisedThenContent)
                {
                    int pol_id = (int)policyItem.Key;

                    Dictionary<string, string> word_m = (Dictionary<string, string>)policyItem.Value;

                    foreach (KeyValuePair<string, string> pair in word_m)
                    {
                        string type = pair.Key;
                        string word = pair.Value;
                        if (type.Equals("temporalconstraint"))
                        {
                            thenTemporalType = word;
                            break;
                        }
                    }
                }
            }
            return thenTemporalType;
        }


        public string getUnlessTemporalType(Policy policy, PolicyStatementAnalyser statAnalyser)
        {
            string unlesstemporalType = null;

            if (!policy.statement.Equals("DO[NILL]"))
            {
                statAnalyser.ifThenUnlessContentTokenisation(policy.statement);
                foreach (DictionaryEntry policyItem in statAnalyser.tokenisedUnlessContent)
                {
                    int pol_id = (int)policyItem.Key;

                    Dictionary<string, string> word_m = (Dictionary<string, string>)policyItem.Value;

                    foreach (KeyValuePair<string, string> pair in word_m)
                    {
                        string type = pair.Key;
                        string word = pair.Value;
                        if (type.Equals("temporalconstraint"))
                        {
                            unlesstemporalType = word;
                            break;
                        }
                    }
                }
            }
            return unlesstemporalType;
        }


        private void pruneThroughAggregateAllTimeHenceforthCacheThreat(List<Object> parameterisedContextInstances_z, Context contextInstance, PolicyStatementAnalyser statAnalyser, List<Threat> newThreats
                                                                    , Agent sendAgent, Agent receiveAgent,Agent subjectAgent, State message_s, Transition message_t)
        {
            int i = 1;
            //List<Threat> newAggregationAllTimeCacheThreatCheckList = new List<Threat>();

            foreach (Threat threat in aggregationAllTimeCacheThreatCheckList)
            {
                bool sameState = false;
                bool sameTransition = false;
                bool sameAgents = false;
                if (threat.message_s != null && message_s != null)
                {
                    if (threat.message_s.name.Equals(message_s.name))
                    {
                        sameState = true;
                    }
                }
                else if (threat.message_t != null && message_t != null)
                {
                    if (threat.message_t.transitionName.Equals(message_t.transitionName))
                    {
                        sameTransition = true;
                    }
                }

                if (threat.sendAgent.agentName.Equals(sendAgent.agentName) &&
                    threat.subjectAgent.agentName.Equals(subjectAgent.agentName) &&
                        threat.recieveAgent.agentName.Equals(receiveAgent.agentName))
                {
                    sameAgents = true;
                }

                if (!(sameAgents && (sameState || sameTransition)))
                {
                    continue;
                }
                ////correlate parameterised context with attributes in threat message_s/t
                //if (threat.message_s != null)
                //{
                //    foreach (Attribute att in threat.message_s.activeAction.parameterisedOperationalAttributes)
                //    {
                //        foreach (Object obj in parameterisedContextInstances_z)
                //        {
                //            Attribute att_p = obj as Attribute;
                //            if (att_p != null)
                //            {
                //                if (att.name.Equals(att_p.name))
                //                {
                //                    att_p.activeDomain = att.activeDomain;
                //                    parameterisedContextInstances_z.Remove(att_p);
                //                    parameterisedContextInstances_z.Add(att);
                //                    break;
                //                }
                //            }
                //        }
                //    }
                //}
                //else if (threat.message_t != null)
                //{
                //    foreach (Attribute att in threat.message_t.activeEvent.parameterisedOperationalAttributes)
                //    {
                //        foreach (Object obj in parameterisedContextInstances_z)
                //        {
                //            Attribute att_p = obj as Attribute;
                //            if (att_p != null)
                //            {
                //                if (att.name.Equals(att_p.name))
                //                {
                //                    att_p.activeDomain = att.activeDomain;
                //                    parameterisedContextInstances_z.Remove(att_p);
                //                    parameterisedContextInstances_z.Add(att);
                //                    break;
                //                }
                //            }
                //        }
                //    }
                //}
                //////

                statAnalyser.ifThenUnlessContentTokenisation(threat.violatedPolicy.statement);
                //bool applicableIFPolicySegment = ApplicableIfTest.applicableIfAnalysis(threat.sendAgent,
                //                                   threat.recieveAgent, threat.subjectAgent, threat.message_s, threat.message_t,
                //                                   parameterisedContextInstances_z, statAnalyser, contextInstance);

                bool applicableIFPolicySegment = true;

                if (applicableIFPolicySegment == true)
                {
                    string thenTemporalType = this.getThenTemporalType(threat.violatedPolicy, statAnalyser);
                    string unlessTemporalType = null;
                    bool thenSatisfied = false;

                    switch (thenTemporalType)
                    {
                        case "ALL-TIME":
                            //DO satisfy previously test and add to allTimeCacheThreatChecks
                            thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_z,
                                                               statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                        case "HENCEFORTH":
                            //DO satisfy previously test and add to allTimeCacheThreatChecks
                            thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_z,
                                                               statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                    }

                    bool unlessSatisfied = false;
                    if (thenSatisfied == false)
                    {
                        unlessTemporalType = this.getUnlessTemporalType(threat.violatedPolicy, statAnalyser);
                        switch (unlessTemporalType)
                        {
                            case "LAST-TIME":
                                unlessSatisfied = SatisfiedLastTimeTest.satisfiedAnalysis(threat.sendAgent, threat.recieveAgent,
                                                                threat.subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "PREVIOUSLY":
                                unlessSatisfied = SatisfiedPreviouslyTest.satisfiedAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "EVENTUALLY":
                                break;
                            case "HENCEFORTH":
                                unlessSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_z,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "NEXT-TIME":
                                break;
                            case "ALL-TIME":
                                //DO satisfy previously test and add to allTimeCacheThreatChecks
                                unlessSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_z,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                        }
                    }
                    if (thenTemporalType.Equals("ALL-TIME") || thenTemporalType.Equals("HENCEFORTH"))
                    {
                        if (thenSatisfied == false && unlessSatisfied == false)
                        {
                            Threat threat_at = new Threat();
                            //threat_at.comments = thenTemporalType + "-AGGREGATION-CHECK";
                            threat_at.comments = "INFERRED-UNFULFILLED-OBLIGATION";
                            threat_at.subjectAgent = threat.subjectAgent;
                            threat_at.sendAgent = threat.sendAgent;
                            threat_at.recieveAgent = threat.recieveAgent;
                            threat_at.violatingParameterisedContextInstances = parameterisedContextInstances_z;
                            threat_at.timestamp = DateTime.Now;
                            threat_at.violatedPolicy = threat.violatedPolicy;
                            if (threat.message_s != null)
                            {
                                threat_at.message_s = threat.message_s;
                            }
                            else if (threat.message_t != null)
                            {
                                threat_at.message_t = threat.message_t;
                            }
                            string hkey = "HContext:" + i;
                            i = i + 1;
                            threat_at.rationales.Add(hkey, getThreatViolatingContext(threat));
                            threat_at.threatType = Threat.ThreatType.currentThreat;
                            //newAggregationAllTimeCacheThreatCheckList.Add(threat);
                            newThreats.Add(threat_at);

                            misuseFound = true;
                        }
                    }
                }
            }

            //if (newAggregationAllTimeCacheThreatCheckList.Count > 0)
            //{
            //    aggregationThreats.Add(newAggregationAllTimeCacheThreatCheckList);
            //}
            allTimeAggregateCall = true;

        }

        private void pruneThroughAggregateCachePotentialThreats(List<Object> parameterisedContextInstances_k, Context contextInstance, PolicyStatementAnalyser statAnalyser, List<Threat> newThreats,
                                                                Agent sendAgent, Agent receiveAgent, Agent subjectAgent, State message_s, Transition message_t)
        {
            List<Threat> cachePrune = new List<Threat>();
            //List<Threat> newAggregationThreats = new List<Threat>();

            foreach (Threat threat in aggregationCachePotentialThreats)
            {
                bool sameState = false;
                bool sameTransition = false;
                bool sameAgents = false;
                if (threat.message_s != null && message_s != null)
                {
                    if (threat.message_s.name.Equals(message_s.name))
                    {
                        sameState = true;
                    }
                }
                else if (threat.message_t != null && message_t != null)
                {
                    if (threat.message_t.transitionName.Equals(message_t.transitionName))
                    {
                        sameTransition = true;
                    }
                }

                if (threat.sendAgent.agentName.Equals(sendAgent.agentName) &&
                    threat.subjectAgent.agentName.Equals(subjectAgent.agentName) &&
                        threat.recieveAgent.agentName.Equals(receiveAgent.agentName))
                {
                    sameAgents = true;
                }

                if (!(sameAgents && (sameState || sameTransition)))
                {
                    continue;
                }
                //correlate parameterised context with attributes in threat message_s/t
                //if (threat.message_s != null)
                //{
                //    foreach (Attribute att in threat.message_s.activeAction.parameterisedOperationalAttributes)
                //    {
                //        foreach (Object obj in parameterisedContextInstances_k)
                //        {
                //            Attribute att_p = obj as Attribute;
                //            if (att_p != null)
                //            {
                //                if (att.name.Equals(att_p.name))
                //                {
                //                    att_p.activeDomain = att.activeDomain;
                //                    parameterisedContextInstances_k.Remove(att_p);
                //                    parameterisedContextInstances_k.Add(att);
                //                    break;
                //                }
                //            }
                //        }
                //    }
                //}
                //else if (threat.message_t != null)
                //{
                //    foreach (Attribute att in threat.message_t.activeEvent.parameterisedOperationalAttributes)
                //    {
                //        foreach (Object obj in parameterisedContextInstances_k)
                //        {
                //            Attribute att_p = obj as Attribute;
                //            if (att_p != null)
                //            {
                //                if (att.name.Equals(att_p.name))
                //                {
                //                    att_p.activeDomain = att.activeDomain;
                //                    parameterisedContextInstances_k.Remove(att_p);
                //                    parameterisedContextInstances_k.Add(att);
                //                    break;
                //                }
                //            }
                //        }
                //    }
                //}
                //////

                statAnalyser.ifThenUnlessContentTokenisation(threat.violatedPolicy.statement);
                //bool applicableIFPolicySegment = ApplicableIfTest.applicableIfAnalysis(threat.sendAgent,
                //                                   threat.recieveAgent, threat.subjectAgent, threat.message_s, threat.message_t,
                //                                   parameterisedContextInstances_k, statAnalyser, contextInstance);
                bool applicableIFPolicySegment = true;

                if (applicableIFPolicySegment == true)
                {
                    string thenTemporalType = this.getThenTemporalType(threat.violatedPolicy, statAnalyser);
                    string unlessTemporalType = null;
                    bool thenSatisfied = false;

                    switch (thenTemporalType)
                    {
                        case "EVENTUALLY":
                            thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                        case "NEXT-TIME":
                            thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedThenContent, contextInstance);
                            break;
                    }

                    bool unlessSatisfied = false;
                    if (thenSatisfied == false)
                    {
                        unlessTemporalType = this.getUnlessTemporalType(threat.violatedPolicy, statAnalyser);
                        switch (unlessTemporalType)
                        {
                            case "LAST-TIME":
                                unlessSatisfied = SatisfiedLastTimeTest.satisfiedAnalysis(threat.sendAgent, threat.recieveAgent,
                                                                threat.subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "PREVIOUSLY":
                                unlessSatisfied = SatisfiedPreviouslyTest.satisfiedAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "EVENTUALLY":
                                thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "NEXT-TIME":
                                thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "HENCEFORTH":
                                thenSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                            case "ALL-TIME":
                                //DO satisfy previously test and add to allTimeCacheThreatChecks
                                unlessSatisfied = NextSatisfactionTest.nextSatisfactionAnalysis(threat.sendAgent, threat.recieveAgent,
                                                               threat.subjectAgent, threat.message_s, threat.message_t, parameterisedContextInstances_k,
                                                               statAnalyser.tokenisedUnlessContent, contextInstance);
                                break;
                        }
                    }
                    if (thenTemporalType.Equals("EVENTUALLY"))
                    {
                        if (thenSatisfied == true || unlessSatisfied == true)
                        {
                            cachePrune.Add(threat);
                        }
                    }
                    if (thenTemporalType.Equals("NEXT-TIME"))
                    {
                        if (thenSatisfied == false && unlessSatisfied == false)
                        {
                            Threat threat_at = new Threat();
                            threat_at.comments = "INFERRED-UNFULFILLED-OBLIGATION";
                            threat_at.subjectAgent = threat.subjectAgent;
                            threat_at.sendAgent = threat.sendAgent;
                            threat_at.recieveAgent = threat.recieveAgent;
                            threat_at.violatingParameterisedContextInstances = parameterisedContextInstances_k;
                            threat_at.timestamp = DateTime.Now;
                            threat_at.violatingParameterisedContextInstances = parameterisedContextInstances_k;
                            threat_at.timestamp = DateTime.Now;
                            threat_at.violatedPolicy = threat.violatedPolicy;
                            if (threat.message_s != null)
                            {
                                threat_at.message_s = threat.message_s;
                            }
                            else if (threat.message_t != null)
                            {
                                threat_at.message_t = threat.message_t;
                            }

                            threat_at.rationalle = "[An expected transmission policy for inferred attribute will not be satisfied by this context]";
                            threat_at.threatType = Threat.ThreatType.futureThreat;

                            //newAggregationThreats.Add(threat);
                            newThreats.Add(threat_at);

                            misuseFound = true;
                        }
                        else
                        {
                            cachePrune.Add(threat);
                        }
                    }
                }
            }

            //if (newAggregationThreats.Count > 0)
            //{
            //    aggregationThreats.Add(newAggregationThreats);

            //}
            foreach (Threat threat in cachePrune)
            {
                foreach (Threat threat1 in aggregationCachePotentialThreats)
                {
                    if (threat.timestamp == threat1.timestamp)
                    {
                        aggregationCachePotentialThreats.Remove(threat1);
                        break;
                    }
                }
            }
        }

    }
}
